package server.console;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import server.exception.InterpreterException;

/**
 * Representa la consola del servidor
 * 
 * @author romeroy
 * 
 */
public class Consola {
	private static final String INPUT_TEST_PATH = "test/server/console/input/";
	private static final String OUTPUT_TEST_PATH = "test/server/console/outputGenerado/";
	
	/**
	 * Lista de objetos que pueden interpretar un comando
	 */
	private List<Interprete> interpretes;

	/**
	 * Historial de comandos ingresados a la consola
	 */
	private List<Orden> history;

	/**
	 * Instancia unica de consola
	 */
	private static Consola instancia;
	
	
	/**
	 * Constructor por defecto
	 */
	private Consola() {
		history = new ArrayList<Orden>();
		interpretes = new ArrayList<Interprete>();
		interpretes.add(new TestInterpreter());
		interpretes.add(new MensajeInterpreter());
		interpretes.add(new ServicioInterpreter());
	}

	/**
	 * Obtiene el historial de comandos
	 * 
	 * @return Lista de comandos ingresados
	 */
	public List<Orden> getHistory() {
		return history;
	}

	/**
	 * Obtiene la lista de interpretes
	 * 
	 * @return Lista de objetos capaces de interpretar un comando
	 */
	public List<Interprete> getInterpretes() {
		return interpretes;
	}

	/**
	 * Ejecuta un comando en la consola
	 * 
	 * @param sentencia
	 *            Sentencia del comando a ejecutar
	 * @return Mensaje resultado de ejecutar el comando
	 */
	public int ejecutar(String sentencia) {
		System.out.println("> " + sentencia);
		if (sentencia == null || "".equals(sentencia) || " ".equals(sentencia))
			return Interprete.NO_RECONOCIDO;
		
		Orden c = new Orden(sentencia);
		history.add(c);

		Iterator<Interprete> i = interpretes.iterator();
		int codigo = Interprete.NO_RECONOCIDO;
		try {
			while (i.hasNext() && codigo == Interprete.NO_RECONOCIDO)
				codigo = i.next().interpretar(c);
		} catch (InterpreterException e) {
			e.printStackTrace();
			return Interprete.ERROR;
		}

		if (codigo == Interprete.NO_RECONOCIDO)
			System.out.println("El comando '"
					+ c.getNombre()
					+ "' no se reconoce como un comando válido de sistema. Verifique su sintaxis");
		return codigo;
	}

	/**
	 * Obtiene una referencia a la instancia unica de consola
	 * 
	 * @return Referencia a instancia unica
	 */
	public static Consola getInstance() {
		if (instancia == null) {
			instancia = new Consola();
		}
		return instancia;
	}
	
	public void setOut(PrintStream out) {
		if(out != null)
			System.setOut(out);
	}
	
	/**
	 * Obtiene ayuda acerca de un comando
	 * @param sentencia Sentencia sobre la cual se espera una ayuda
	 * @return String
	 */
	public String obtenerAyuda(String sentencia) {
		Iterator<Interprete> i = interpretes.iterator();
		String help = null;
		while (i.hasNext() && help == null)
			help = i.next().getTooltip(sentencia);
		return help;
	}

	public static void main(String[] args) {
		double inicio, fin;
		Consola c = Consola.getInstance();
		
		
		try {
		BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("Escriba exit para salir");
		System.out.print("> ");
		String linea = keyboard.readLine();
		while(!linea.equalsIgnoreCase("exit")) {
			c.ejecutar(linea);
			System.out.print("> ");
			linea = keyboard.readLine();
		}
		
			// Abro carpeta test/input
			File directorio = new File(Consola.INPUT_TEST_PATH);
			String nombre;
			
			// Recorro los archivos uno a uno
			for (File archivo : directorio.listFiles()) {

				// Obtengo el nombre del archivo
				nombre = archivo.getName();
				nombre = nombre.split("\\.")[0];

				// Ejecuto la prueba
				try {
					FileReader file = new FileReader(new File(Consola.INPUT_TEST_PATH + nombre + ".in"));
					BufferedReader in = new BufferedReader(file);
					PrintStream out = new PrintStream(new File(Consola.OUTPUT_TEST_PATH + nombre + ".out"));
					PrintStream old = System.out;
					
					try {
						String sentencia = in.readLine();
						
						c.setOut(out);
						// Ejecuto comando
						inicio = System.currentTimeMillis();
						c.ejecutar(sentencia);
						fin = System.currentTimeMillis();
						
						c.setOut(old);
						// Muestro tiempo utilizado
						System.out.println(nombre + ": " + (fin - inicio) + " ms");
						
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						file.close();
						out.close();
					}

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
}
